﻿using Face8280WebSocketServer.Controllers.FaceDevice;
using Face8280WebSocketServer.Interface;
using Face8280WebSocketServer.Utility.FilterAttribute;
using Face8280WebSocketServer.Utility.Model;
using Face8280WebSocketServer.Command;
using Face8280WebSocketServer.Command.IPPar;
using Face8280WebSocketServer.Command.WorkParameter;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Linq.Expressions;
using AutoMapper;
using DoNetDrive.AspWebSocke.WebSocketClient;
using Face8280WebSocketServer.Command.Remote;
using Face8280WebSocketServer.DB.NewModel.Device;
using DoNetDrive.Core.Command;
using FaceFace8280WebSocketServer.Controllers.New.FaceDevice;
using Face8280WebSocketServer.Command.CommandDetail;
using Face8280WebSocketServer.DTO.FaceDevice;
using Face8280WebSocketServer.DB.Device;
using Microsoft.Net.Http.Headers;
using Microsoft.AspNetCore.WebUtilities;
using Newtonsoft.Json.Serialization;
using System.Security.Cryptography;
using Face8280WebSocketServer.Utility;
using Face8280WebSocketServer.Command.Models;
using Face8280WebSocketServer.Command.Person;

namespace Face8280WebSocketServer.Controllers.New.FaceDevice
{
    [Route("api/[controller]")]
    [ApiController]
    public class FaceDeviceNewController : ControllerBase
    {
        private readonly ILogger<FaceDeviceNewController> _logger;
        private IFaceDriveServiceNew _DeviceDB;
        ICacheService CacheService;
        IMapper _Mapper;
        IFaceIOLogService _FaceIOLogService;
        public FaceDeviceNewController(ILogger<FaceDeviceNewController> logger, IFaceDriveServiceNew door,
            IMapper mapper,
            ICacheService cacheService,
            IFaceIOLogService faceIOLogService)
        {
            _logger = logger;
            _DeviceDB = door;
            _Mapper = mapper;
            CacheService = cacheService;
            _FaceIOLogService = faceIOLogService;
        }
        [HttpPost]
        [Route("AddDevice")]
        [Authorize]
        [TypeFilter(typeof(VerifyActionFilterAttribute))]
        public async Task<IActionResult> AddDevice([FromForm] AddDeviceParameter parameter)
        {
            return new JsonResult(await AddDeviceInfo(parameter));
        }

        private async Task<JsonResultModel> AddDeviceInfo(AddDeviceParameter parameter)
        {
            if (string.IsNullOrWhiteSpace(parameter.DeviceSN))
                parameter.DeviceSN = Guid.NewGuid().ToString();
            FaceDriveCommand command = new FaceDriveCommand();
            var deviceInfo = await command.GetDeviceWorkParameter(parameter);
            if (deviceInfo == null)
            {
                return new JsonResultModel(101, "获取设备信息失败");
            }

            if (string.IsNullOrWhiteSpace(deviceInfo.DeviceSn) ||
                deviceInfo.DeviceSn.Length < 15 ||
                deviceInfo.DeviceSn == "0000000000000000")
            {
                var update = UpdateDeviceDetailParameter.clone(deviceInfo);
                update.OldDeviceSn = deviceInfo.DeviceSn;
                deviceInfo.DeviceSn = _DeviceDB.GetDefaultSn();
                update.DeviceSn = deviceInfo.DeviceSn;
                var setResult = await command.SetDeviceWorkParameter(await Allocator.GetCommandDetail(parameter.DeviceSN), update);
                if (setResult == null || setResult.JsonResultValue.Result != 200)
                {
                    return new JsonResultModel(100, "写入设备参数失败" + setResult.JsonResultValue.Error);
                }
            }
            Allocator.UpdateWebSocketClientDetail(parameter.DeviceSN, deviceInfo.DeviceSn, "");
            var result = _DeviceDB.AddDevice(deviceInfo);
            CacheService.AddDeviceCache(deviceInfo);
            return result;
        }
        [HttpPost]
        [Route("AddDevices")]
        [Authorize]
        [TypeFilter(typeof(VerifyActionFilterAttribute))]
        public async Task<IActionResult> AddDevices([FromForm] AddDevicesParameter parameter)
        {
            if (parameter == null || parameter.Devices == null)
            {
                return new JsonResult(new JsonResultModel(100, "参数错误"));
            }
            if (parameter.Devices.Count == 0)
            {
                return new JsonResult(new JsonResultModel(100, "请选择需要添加的设备"));
            }
            var resultList = new List<JsonResultModel>();
            foreach (var item in parameter.Devices)
            {
                var result = await AddDeviceInfo(new AddDeviceParameter
                {
                    ConnectType = 0,
                    DeviceName = item.SN,
                    DeviceSN = item.SN,
                    IPAddress = item.IP,
                    Port = item.Port,
                    Token = parameter.Token
                });
                result.content = item.SN;
                resultList.Add(result);
            }
            var jsonResult = new JsonResultModel
            {
                content = resultList
            };
            return new JsonResult(jsonResult);
        }
        //  private UpdateDeviceDetailParameter 
        /// <summary>
        /// 获取设备列表数据
        /// </summary>
        /// <param name="par"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("GetDeviceTable")]
        [Authorize]
        [TypeFilter(typeof(VerifyActionFilterAttribute))]
        public IActionResult GetDeviceTable([FromForm] DeviceQueryParameter par)
        {
            //添加 Lambda 查询条件
            List<Expression<Func<FaceDeviceInfo, bool>>> oWhere = new();
            if (!string.IsNullOrWhiteSpace(par.DeviceName)) oWhere.Add(a => a.DeviceName.Contains(par.DeviceName));
            if (!string.IsNullOrWhiteSpace(par.DeviceID)) oWhere.Add(a => a.DeviceSn.Contains(par.DeviceID));
            return new JsonResult(new JsonResultModel(_DeviceDB.GetDevicePage(oWhere, par)));
        }


        /// <summary>
        /// 获取设备详情
        /// </summary>
        /// <param name="par"></param>
        /// <returns></returns>
        [HttpGet]
        [Route("GetDeviceDetail/{sn}")]
        [Authorize]
        public IActionResult GetDeviceDetail(string sn)
        {
            return new JsonResult(new JsonResultModel(_DeviceDB.GetFaceDeviceById(sn)));
        }
        /// <summary>
        /// 从设备获取设备详情
        /// </summary>
        /// <param name="par"></param>
        /// <returns></returns>
        [HttpGet]
        [Route("ReadDeviceDetail/{id}")]
        [Authorize]
        public async Task<IActionResult> ReadDeviceDetail(int id)
        {
            var tabentity = _DeviceDB.GetFaceDeviceById(id);
            if (tabentity == null)
            {
                return new JsonResult(new JsonResultModel(101, "没有找到设备"));
            }
            FaceDriveCommand command = new FaceDriveCommand();
            var deviceInfo = await command.GetDeviceWorkParameter(tabentity.DeviceSn);
            if (deviceInfo == null)
            {
                return new JsonResult(new JsonResultModel(101, "获取设备信息失败"));
            }
            // _Mapper.Map(deviceInfo, tabentity);
            deviceInfo.DeviceIP = tabentity.DeviceIP;
            deviceInfo.DevicePort = tabentity.DevicePort;
            deviceInfo.DeviceName = tabentity.DeviceName;
            deviceInfo.DeviceSn = tabentity.DeviceSn;
            deviceInfo.Id = tabentity.Id;
            //  _FaceIOLogService.AddIOLog(log);
            return new JsonResult(new JsonResultModel(deviceInfo));
        }

        [HttpPost]
        [Route("UpdateDeviceDetail")]
        [Authorize]

        public async Task<IActionResult> UpdateDeviceDetail([FromForm] UpdateDeviceDetailParameter par)
        {
            INCommandDetail detail;
            var deviceinfo = _DeviceDB.GetFaceDeviceById(par.Id);
            if (Allocator.WebSocketClients.ContainsKey(deviceinfo.DeviceSn))
            {
                detail = await Allocator.GetCommandDetail(Allocator.WebSocketClients[deviceinfo.DeviceSn]);
            }
            else if (Allocator.WebSocketServerClients.ContainsKey(deviceinfo.DeviceSn))
            {
                detail = Allocator.GetCommandDetail(Allocator.WebSocketServerClients[deviceinfo.DeviceSn]);
            }
            else
            {
                return new JsonResult(new JsonResultModel(1, "设备不存在"));
            }
            //  var deviceinfo = _DeviceDB.GetFaceDeviceById(par.Id);
            //if (detail == null)
            //{
            //    detail = Allocator.GetCommandDetail(deviceinfo.DeviceSn, deviceinfo.DeviceIP, deviceinfo.DevicePort, deviceinfo.Token);
            //}
            var newToke = string.Empty;
            var newSn = string.Empty;
            if (!par.Token.Equals(deviceinfo.Token))
            {
                par.OldToken = deviceinfo.Token;
                newToke = par.Token;
            }
            if (!par.DeviceSn.Equals(deviceinfo.DeviceSn))
            {
                newSn = par.DeviceSn;
                par.OldDeviceSn = deviceinfo.DeviceSn;
            }
            FaceDriveCommand command = new();
            var result = await command.SetDeviceWorkParameter(detail, par);
            if (result == null || result.JsonResultValue.Result != 200)
            {
                return new JsonResult(new JsonResultModel(101, "写入失败:" + result.JsonResultValue.Error));
            }
            Allocator.UpdateWebSocketClientDetail(deviceinfo.DeviceSn, newSn, newToke);
            par.ConnectType = deviceinfo.ConnectType;
            par.DeviceName = deviceinfo.DeviceName;
            par.DeviceIP = deviceinfo.DeviceIP;
            par.DevicePort = deviceinfo.DevicePort;
            return new JsonResult(_DeviceDB.AddDevice(par));
        }

        [HttpPost]
        [Route("DeleteDevice")]
        [Authorize]
        [TypeFilter(typeof(VerifyActionFilterAttribute))]
        public IActionResult DeleteDevice([FromForm] string id)
        {
            if (id != null)
            {
                var idSplit = id.TrimEnd(',').Split(',');
                var idArray = Array.ConvertAll(idSplit, a => int.Parse(id));
                if (idArray.Length > 0)
                {
                    _DeviceDB.DeleteDeviceRange(idArray);
                    var devices = CacheService.GetDevices().Where(a => idArray.Contains(a.Id));
                    foreach (var item in devices)
                    {
                        CacheService.DeleteDeviceCache(item.DeviceSn);
                        Allocator.WebSocketClients.TryRemove(item.DeviceSn, out _);
                    }
                }
            }
            return new JsonResult(new JsonResultModel());
        }

        /// <summary>
        /// 上传固件文件
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("UploadDeviceSoftFile")]
        public async Task<IActionResult> UploadDeviceSoftFile()
        {
            var request = HttpContext.Request;
            var ecr = System.Text.Encoding.UTF8;

            // validation of Content-Type
            // 1. first, it must be a form-data request
            // 2. a boundary should be found in the Content-Type
            if (!request.HasFormContentType ||
                !MediaTypeHeaderValue.TryParse(request.ContentType, out var mediaTypeHeader) ||
                string.IsNullOrEmpty(mediaTypeHeader.Boundary.Value))
            {
                return new UnsupportedMediaTypeResult();
            }

            var reader = new MultipartReader(mediaTypeHeader.Boundary.Value, request.Body);
            var section = await reader.ReadNextSectionAsync();
            var dicValue = new Dictionary<string, string>();
            // This sample try to get the first file from request and save it
            // Make changes according to your needs in actual use
            while (section != null)
            {
                var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition,
                    out var contentDisposition);

                if (hasContentDispositionHeader && contentDisposition.DispositionType.Equals("form-data") &&
                    !string.IsNullOrEmpty(contentDisposition.FileName.Value))
                {
                    // Don't trust any file name, file extension, and file data from the request unless you trust them completely
                    // Otherwise, it is very likely to cause problems such as virus uploading, disk filling, etc
                    // In short, it is necessary to restrict and verify the upload
                    // Here, we just use the temporary folder and a random file name

                    // Get the temporary folder, and combine a random file name with it
                    var sfilename = Path.GetFileName(contentDisposition.FileName.Value);

                    if (dicValue.ContainsKey("fileName"))
                    {
                        return new JsonResult(new JsonResultModel(1, "一次仅允许上传一个文件"));
                    }
                    dicValue.Add("fileName", sfilename);
                    if (!sfilename.EndsWith(".pkg"))
                    {
                        return new JsonResult(new JsonResultModel(2, "文件后缀不正确"));
                    }
                    var _targetFilePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "softpkg", sfilename);

                    using (var targetStream = System.IO.File.Create(_targetFilePath))
                    {
                        await section.Body.CopyToAsync(targetStream);
                    }
                    var fileinfo = new FileInfo(_targetFilePath);
                    dicValue.Add("fileSize", fileinfo.Length.ToString());
                    dicValue.Add("filePath", _targetFilePath);
                    if (fileinfo.Length < 300 * 1024 * 1024)
                    {
                        System.IO.File.Delete(_targetFilePath);
                        return new JsonResult(new JsonResultModel(3, "文件太小"));
                    }
                    _logger.LogInformation($"上传大文件接口，文件名:{contentDisposition.FileName.Value}，文件大小：{fileinfo.Length}");
                    //验证文件合法性
                    string sHex;
                    using (var stm = System.IO.File.OpenRead(_targetFilePath))
                    {
                        byte[] buf = new byte[10];
                        stm.Read(buf, 0, 10);
                        sHex = buf.ToHex();

                    }
                    if (sHex != "20504B20000000001100")
                    {
                        System.IO.File.Delete(_targetFilePath);
                        return new JsonResult(new JsonResultModel(4, "文件特征不正确"));
                    }
                }
                else
                {
                    using (var targetStream = new MemoryStream())
                    {
                        await section.Body.CopyToAsync(targetStream);
                        targetStream.Position = 0;
                        byte[] buf = new byte[targetStream.Length];
                        targetStream.Read(buf, 0, (int)targetStream.Length);
                        string value = ecr.GetString(buf);
                        _logger.LogInformation($"上传大文件接口，参数名:{contentDisposition.Name.Value}，值：{value}");

                        dicValue.Add(contentDisposition.Name.Value, value);
                    }
                }

                section = await reader.ReadNextSectionAsync();
            }

            if (!dicValue.ContainsKey("fileName"))
            {
                return new JsonResult(new JsonResultModel(5, "请上传文件"));
            }

            if (!dicValue.ContainsKey("softName") || string.IsNullOrWhiteSpace(dicValue["softName"]))
            {
                return new JsonResult(new JsonResultModel(6, "固件名称不能为空"));
            }
            if (dicValue["softName"].Length < 5)
            {
                return new JsonResult(new JsonResultModel(6, "固件名称太短"));
            }


            if (!dicValue.ContainsKey("softVer") || string.IsNullOrWhiteSpace(dicValue["softVer"]))
            {
                return new JsonResult(new JsonResultModel(7, "固件版本不能为空"));
            }
            if (dicValue["softVer"].Length != 4 || !dicValue["softVer"].IsNum())
            {
                return new JsonResult(new JsonResultModel(6, "固件版本必须是4位数字"));
            }

            var settingFile = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "softpkg", "softsetting.json");
            var settingJson = System.IO.File.ReadAllText(settingFile);
            var oDetailList = settingJson.FromJson<softDetailList>();
            var sFileName = dicValue["fileName"];
            var hash = new Dictionary<string, softDetail>();

            foreach (var item in oDetailList.list)
            {
                hash.Add(item.url, item);
            }
            softDetail detail = null;
            if (hash.ContainsKey(sFileName))
            {
                //已存在
                detail = hash[sFileName];
            }
            else
            {
                detail = new softDetail()
                {
                    url = sFileName
                };
                hash.Add(sFileName, detail);
                oDetailList.list.Insert(0, detail);
            }
            detail.md5 = MD5Utility.GetFileMD5(dicValue["filePath"]);
            detail.name = dicValue["softName"];
            detail.ver = dicValue["softVer"];
            settingJson = oDetailList.ToJson();
            System.IO.File.WriteAllText(settingFile, settingJson, ecr);
            return new JsonResult(new JsonResultModel());
        }

        /// <summary>
        /// 设置设备出厂默认值
        /// </summary>
        /// <param name="par"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("UpdateDeviceSoft")]
        [Authorize]
        [TypeFilter(typeof(VerifyActionFilterAttribute))]
        public async Task<IActionResult> UpdateDeviceSoft(
            [FromForm] string SoftName, [FromForm] string Ver, [FromForm] string SoftMD5, [FromForm] int DeviceID)
        {
            var oDevice = _DeviceDB.Find<FaceDeviceInfo>(DeviceID);
            if (oDevice == null)
                return new JsonResult(new JsonResultModel(1, "设备不存在"));
            //  string sURL = SoftName;
            if (!SoftName.StartsWith("http"))
            {
                var sPath = System.IO.Directory.GetCurrentDirectory();
                sPath = Path.Combine(sPath, "wwwroot", "softpkg");
                var sFile = Path.Combine(sPath, SoftName);
                if (!System.IO.File.Exists(sFile))
                {
                    return new JsonResult(new JsonResultModel(2, "固件文件不存在"));
                }
                using System.IO.FileStream fileStream = new System.IO.FileStream(sFile, FileMode.Open);
                var md5 = MD5Utility.GetFileMD5(fileStream);
                if (!md5.Equals(SoftMD5))
                {
                    return new JsonResult(new JsonResultModel(3, "固件文件MD5校验失败！"));
                }
                //if (!SoftName.Contains(Ver))
                //{
                //    return new JsonResult(new JsonResultModel(4, "固件文件版本号验证失败！"));
                //}
                // sURL = $"/softpkg/{SoftName}";

                var cmdDil = await Allocator.GetCommandDetail(oDevice.DeviceSn);
                cmdDil.Timeout = 15000;
                PushSoftware cmd = new PushSoftware(cmdDil, Ver, fileStream, "test", md5);
                await Allocator.AddCommandAsync(cmd);
                var result = cmd.getResult() as CommandResult;
                if (result == null || result.ResultObj.Result != 200)
                {
                    int iErr = result?.ResultObj?.Result ?? 100;
                    return new JsonResult(new JsonResultModel(iErr, result?.ResultObj?.Error));
                }
                return new JsonResult(new JsonResultModel());
            }
            return new JsonResult(new JsonResultModel(100, "固件地址错误"));
        }
        [HttpPost]
        [Route("SearchDevice")]
        [Authorize]
        [TypeFilter(typeof(VerifyActionFilterAttribute))]
        public async Task<IActionResult> SearchDevice()
        {
            var result = await Allocator.SearchDevice();
            PageResult<DeviceSerach> page = new PageResult<DeviceSerach>();
            if (result != null && result.Count > 0)
            {
                var devices = CacheService.GetDevices();

                foreach (var item in result)
                {
                    foreach (var device in devices)
                    {
                        if (item.SN.Equals(device.DeviceSn))
                        {
                            item.IsAdd = true;
                        }
                    }
                }

                page.DataList = result;
                page.PageIndex = 1;
                page.PageSize = result.Count;
                page.TotalCount = result.Count;
            }
            return new JsonResult(new JsonResultModel(page));
        }

        /// <summary>
        /// 获取设备在线状态
        /// </summary>
        /// <param name="par"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("GetDeviceOnlineStatus")]
        [Authorize]
        [TypeFilter(typeof(VerifyActionFilterAttribute))]
        public IActionResult GetDeviceOnlineStatus([FromForm] List<string> SNList)
        {
            return new JsonResult(new JsonResultModel(_DeviceDB.GetDeviceOnlineStatus(SNList)));
        }
        /// <summary>
        /// 写入网络参数
        /// </summary>
        /// <param name="par"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("WriteNetWork")]
        [Authorize]
        [TypeFilter(typeof(VerifyActionFilterAttribute))]
        public async Task<IActionResult> WriteNetWork([FromForm] WriteNetWorkParameter parameter)
        {

            INCommandDetail detail;
            var deviceinfo = _DeviceDB.GetFaceDeviceById(parameter.DeviceId);
            if (deviceinfo == null)
            {
                return new JsonResult(new JsonResultModel(1, "设备不存在"));
            }
            if (Allocator.WebSocketClients.ContainsKey(deviceinfo.DeviceSn))
            {
                detail = await Allocator.GetCommandDetail(Allocator.WebSocketClients[deviceinfo.DeviceSn]);
            }
            else if (Allocator.WebSocketServerClients.ContainsKey(deviceinfo.DeviceSn))
            {
                detail = Allocator.GetCommandDetail(Allocator.WebSocketServerClients[deviceinfo.DeviceSn]);
            }
            else
            {
                return new JsonResult(new JsonResultModel(1, "设备不存在"));
            }
            var data = GetIP_DTO(parameter);
            var cmd = new SetIPPar(detail, data);
            await Allocator.AddCommandAsync(cmd);
            var result = cmd.getResult() as SetIPParResult;
            if (result.JsonResultValue.Result != 200)
            {
                return new JsonResult(new JsonResultModel(result.JsonResultValue.Result, result.JsonResultValue.Error));
            }
            _DeviceDB.UpdateNetWork(parameter);
            return new JsonResult(new JsonResultModel());
        }

        private SetIPPar_DTO GetIP_DTO(WriteNetWorkParameter parameter)
        {
            var data = new SetIPPar_DTO()
            {
                Ip = new IpModel
                {
                    Ip = parameter.IIp,
                    Dhcp = parameter.IDhcp,
                    Dns = parameter.IDns,
                    Gateway = parameter.IGateway,
                    Mac = parameter.IMac,
                    Mask = parameter.IMask,
                    Ssl = parameter.ISsl,
                    Tcp = parameter.ITcp,
                    Udp = parameter.IUdp,
                    Websocket = parameter.IWebsocket,
                    Keepalive = parameter.IKeepalive,
                },
                //Server = new WebsocketServerModel
                //{
                //    Server = parameter.WSServer,
                //    Keepalive = parameter.WSKeepalive,
                //    Keeptime = parameter.WSKeeptime,
                //    Port = parameter.WSPort,
                //    ReconnectTime = parameter.WSReconnectTime,
                //    ServerSSLCert = parameter.WSServerSSLCert,
                //    Status = parameter.WSStatus,
                //    Token = parameter.WSToken
                //},
                WiFi = new WiFiModel()
                {
                    Name = parameter.WiFiName,
                    Password = parameter.WiFiPassword,
                    Use = parameter.WiFiUse,
                }
            };
            return data;
        }

    }
}
